import 'package:flutter/material.dart';

/// 默认执行动画时间
const Duration _defaultAnimationTime = Duration(milliseconds: 1000);

/// 构建浮动的控件，传递给外部此刻是否为浮动模式
typedef Widget _FloatingWidgetBuilder(BuildContext context, bool isFloating);

/// 多个动画控制器对应的模式，通过它在某些阶段对应某些动画
enum _AnimatedMode {
  /// 滑动
  Slide,

  /// 浮动
  Floating,

  /// 拖拽
  Drag
}

/// 执行对应的缩放完毕的页面位置
enum ScreenPosition {
  /// 上左
  topLeft,

  /// 上右
  topRight,

  /// 下左
  bottomLeft,

  /// 下右
  bottomRight,
}

class PictureInPicture extends StatefulWidget {
  /// 默认缩放后位置
  final ScreenPosition defaultPosition;

  /// 悬浮窗口的大小
  final double floatingWindowWidth;
  final double floatingWindowHeight;

  /// 距离边上有多少间距
  final double spacing;

  /// 构建器
  final _FloatingWidgetBuilder builder;

  const PictureInPicture({
    Key? key,
    required this.builder,
    this.defaultPosition = ScreenPosition.bottomRight,
    required this.floatingWindowWidth,
    required this.floatingWindowHeight,
    this.spacing = 0,
  })  : assert(spacing >= 0),
        super(key: key);

  @override
  PictureInPictureState createState() => PictureInPictureState();

  static PictureInPictureState? of(BuildContext context) {
    return context.findAncestorStateOfType<PictureInPictureState>();
  }
}

class PictureInPictureState extends State<PictureInPicture> with TickerProviderStateMixin {
  /// 动画控制器
  /// 悬浮控制
  late final AnimationController _toggleFloatingAnimationController = AnimationController(
    duration: _defaultAnimationTime,
    vsync: this,
  );

  /// 默认进行执行一次push效果
  /// 进来页面push效果
  late final AnimationController _slideAnimationController = AnimationController(
    vsync: this,
    duration: _defaultAnimationTime,
  )..forward();

  /// 拖拽
  late final AnimationController _dragAnimationController = AnimationController(
    duration: _defaultAnimationTime,
    vsync: this,
  );

  /// 动画交互
  late final Animation<Offset> _slideOffsetAnimation = Tween<Offset>(
    begin: Offset(1, 0),
    end: Offset.zero,
  ).animate(
    CurvedAnimation(parent: _slideAnimationController, curve: Curves.linear),
  );

  /// 默认模式为滑动为进入页面的push
  _AnimatedMode _animatedMode = _AnimatedMode.Slide;

  /// 是否浮动了
  bool _isFloating = false;

  Offset _dragOffset = Offset.zero;
  bool _isDragging = false;

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    _toggleFloatingAnimationController.dispose();
    _slideAnimationController.dispose();
    _dragAnimationController.dispose();
    super.dispose();
  }

  /// 是否正在动画执行中
  bool _isAnimating() {
    return _toggleFloatingAnimationController.isAnimating ||
        _slideAnimationController.isAnimating ||
        _dragAnimationController.isAnimating;
  }

  /// 获取对应的position参数的offset数据
  Offset _getPositionOffset(
    ScreenPosition position,
    Size floatingSize,
    Size fullWidgetSize,
  ) {
    /// 可能有键盘弹起的时候
    final EdgeInsets windowPadding = MediaQuery.of(context).padding + MediaQuery.of(context).viewInsets;
    final double left = widget.spacing + windowPadding.left;
    final double top = widget.spacing + windowPadding.top;
    final double right = fullWidgetSize.width - floatingSize.width - windowPadding.right - widget.spacing;
    final double bottom = fullWidgetSize.height - floatingSize.height - windowPadding.bottom - widget.spacing;

    switch (position) {
      case ScreenPosition.topLeft:
        {
          return Offset(left, top);
        }
      case ScreenPosition.topRight:
        {
          return Offset(left, bottom);
        }
      case ScreenPosition.bottomLeft:
        {
          return Offset(left, bottom);
        }
      case ScreenPosition.bottomRight:
        {
          return Offset(right, bottom);
        }
      default:
        throw UnimplementedError('Not implemented position params');
    }
  }

  /// 退出Overlay模式动画
  Future<void> exitAnimated() async {
    if (_isAnimating()) return;

    /// 判断是否已经执行浮动动画
    if (_toggleFloatingAnimationController.value == 0) {
      await _slideAnimationController.reverse();
    }
  }

  /// 开始浮动
  Future<void> startFloating() async {
    if (_isAnimating()) return;
    if (FocusScope.of(context).hasFocus) {
      FocusScope.of(context).requestFocus(FocusNode());
    }
    _isFloating = true;
    _animatedMode = _AnimatedMode.Floating;
    await _toggleFloatingAnimationController.forward();
  }

  /// 停止浮动
  Future<void> stopFloating() async {
    if (_isAnimating()) return;
    if (FocusScope.of(context).hasFocus) {
      FocusScope.of(context).requestFocus(FocusNode());
    }
    _isFloating = false;
    await _toggleFloatingAnimationController.reverse();
  }

  // void _onPanUpdate(DragUpdateDetails details) {
  //   if (!_isDragging) return;
  //   setState(() {
  //     _dragOffset = _dragOffset.translate(
  //       details.delta.dx,
  //       details.delta.dy,
  //     );
  //   });
  // }
  //
  // void _onPanCancel() {
  //   if (!_isDragging) return;
  //   setState(() {
  //     _dragAnimationController.value = 0;
  //     _dragOffset = Offset.zero;
  //     _isDragging = false;
  //   });
  // }
  //
  // void _onPanEnd(DragEndDetails details) {
  //   if (!_isDragging) return;
  //
  //   final nearestCorner = _calculateNearestCorner(
  //     offset: _dragOffset,
  //     offsets: _offsets,
  //   );
  //   setState(() {
  //     _corner = nearestCorner;
  //     _isDragging = false;
  //   });
  //   _dragAnimationController.forward().whenCompleteOrCancel(() {
  //     _dragAnimationController.value = 0;
  //     _dragOffset = Offset.zero;
  //   });
  // }
  //
  // void _onPanStart(DragStartDetails details) {
  //   if (_isAnimating()) return;
  //   setState(() {
  //     _dragOffset = _offsets[_corner]!;
  //     _isDragging = true;
  //   });
  // }

  @override
  Widget build(BuildContext context) {
    print("页面开始渲染");
    return LayoutBuilder(
      builder: (context, constraints) {
        print("LayoutBuilder更新");

        /// 对应的需要缩放的视图数据
        final double width = constraints.maxWidth,
            height = constraints.maxHeight,
            floatingWidth = widget.floatingWindowWidth,
            floatingHeight = widget.floatingWindowHeight,
            widthRatio = floatingWidth / width,
            heightRatio = floatingHeight / height;

        /// 浮动大小数据和layout builder数据尺寸
        final Size floatingWidgetSize = Size(floatingWidth, floatingHeight), fullWidgetSize = Size(width, height);

        /// 计算用户传递进来的位置所属,进行对应的偏移量offset计算
        final Offset calculatedOffset = _getPositionOffset(widget.defaultPosition, floatingWidgetSize, fullWidgetSize);

        /// 比例缩放
        final double scaledDownScale = widthRatio > heightRatio
            ? floatingWidgetSize.width / fullWidgetSize.width
            : floatingWidgetSize.height / fullWidgetSize.height;

        /// transfrom的值都是用水平动画来的
        final CurveTween animationCurve = CurveTween(curve: Curves.linear);

        /// 要在画板上操作，不使用stack可以把画板偏移了
        return Stack(
          children: <Widget>[
            AnimatedBuilder(
              animation: Listenable.merge([
                _slideAnimationController,
                _toggleFloatingAnimationController,
                // _dragAnimationController,
              ]),
              builder: (context, child) {
                if (_animatedMode == _AnimatedMode.Slide) {
                  return SlideTransition(position: _slideOffsetAnimation, child: child);
                }
                final dragAnimationValue = animationCurve.transform(_dragAnimationController.value);

                /// 浮动动画的值
                final toggleFloatingAnimationValue = animationCurve.transform(_toggleFloatingAnimationController.value);
                final floatingOffset = _isDragging
                    ? _dragOffset
                    : Tween<Offset>(
                        begin: _dragOffset,
                        end: calculatedOffset,
                      ).transform(
                        _dragAnimationController.isAnimating ? dragAnimationValue : toggleFloatingAnimationValue);

                /// size transition动画定位最终大小不好裁定，使用transform的值
                final double animationWidth = Tween<double>(
                  begin: fullWidgetSize.width,
                  end: floatingWidgetSize.width,
                ).transform(toggleFloatingAnimationValue);

                final double animationHeight = Tween<double>(
                  begin: fullWidgetSize.height,
                  end: floatingWidgetSize.height,
                ).transform(toggleFloatingAnimationValue);

                /// transform圆角的值(变化太快，在动画运行看不出效果)
                /// final double borderRadius = Tween<double>(begin: 0, end: 8).transform(toggleFloatingAnimationValue);

                Widget animatedLayout = Material(
                  borderRadius: BorderRadius.circular(8),
                  child: Container(
                    clipBehavior: Clip.hardEdge,
                    decoration: BoxDecoration(
                      color: Colors.transparent,
                      borderRadius: BorderRadius.circular(8),
                    ),
                    width: animationWidth,
                    height: animationHeight,
                    child: ScaleTransition(
                      scale: Tween<double>(begin: 1, end: scaledDownScale).animate(
                        _toggleFloatingAnimationController,
                      ),
                      child: OverflowBox(
                        maxHeight: fullWidgetSize.height,
                        maxWidth: fullWidgetSize.width,
                        child: IgnorePointer(ignoring: _isFloating, child: child),
                      ),
                    ),
                  ),
                );

                /// 在动画执行过程中,不绑定没用的视图
                if (_toggleFloatingAnimationController.isCompleted) {
                  animatedLayout = GestureDetector(onTap: stopFloating, child: animatedLayout);
                }

                /// 直接使用偏移量的值
                return Transform.translate(
                  offset: Offset(floatingOffset.dx, floatingOffset.dy),
                  child: animatedLayout,
                );
              },
              child: Builder(
                builder: (BuildContext context) {
                  print("builder子类更新了");
                  return widget.builder(context, _isFloating);
                },
              ),
            ),
          ],
        );
      },
    );
  }
}
